package service

import (
	"blog/app/dto"
	"blog/app/models"
	"blog/app/repo"
	"blog/config"
	"blog/utils"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"go.mongodb.org/mongo-driver/bson"
	"gorm.io/gorm"
)

// GetUserList 获取用户列表
func GetUserList(c *gin.Context) {
	var userModel []models.UserBasic
	err := utils.MySqlDB.Model(&userModel).Find(&userModel).Error
	if err != nil {
		fmt.Println("获取数据失败", err)
		CommonCJsonReply(c, config.ERROR, "获取数据失败")
		return
	}
	CommonCJsonReply(c, config.SUCCESS, userModel)
}

// CreateUser 新建用户
func CreateUser(c *gin.Context) {
	var userModel models.UserBasic
	err := utils.MySqlDB.Model(&userModel).Find(&userModel).Error
	if err != nil {
		CommonCJsonReply(c, config.ERROR, err.Error())
		return
	}
	CommonCJsonReply(c, config.SUCCESS, userModel)
}

// 轮播图接口
//func GetBannerList(c *gin.Context) {
//    var bannerList []models.Banner
//    err := config.DB.Find(&bannerList).Error
//    if err != nil {
//        fmt.Println("查询失败", err)
//        return
//    }
//    CommonCJsonReply(c, 200, bannerList)
//}

// MySQL事务处理 -- 自动化事务
func tranMysql() {
	db := utils.MySqlDB
	// 自动化事务
	err := db.Transaction(func(tx *gorm.DB) error {

		getUUid := utils.RandUuid()

		if err := tx.Create(&models.User{
			UserID:          getUUid,
			TaiUserName:     utils.GetRandChineseName(),
			UserName:        utils.GetRandName(10, false),
			UserChineseName: utils.GetRandChineseName(),
			NeedCard:        0,
			AuthStartDate:   "",
			AuthEndDate:     "",
			Status:          0,
			OrgType:         0,
			UpdateTime:      time.Now(),
			Phone:           "",
			ConcatPeople:    "",
			IDNumber:        "",
			CreateBy:        "",
		}).Error; err != nil {
			fmt.Println("提交失败1,回滚", err.Error())
			return err
		}

		if err := tx.Create(&models.User{
			UserID:          getUUid,
			TaiUserName:     utils.GetRandChineseName(),
			UserName:        utils.GetRandName(10, false),
			UserChineseName: utils.GetRandChineseName(),
			NeedCard:        0,
			AuthStartDate:   "",
			AuthEndDate:     "",
			Status:          0,
			OrgType:         0,
			UpdateTime:      time.Now(),
			Phone:           "",
			ConcatPeople:    "",
			IDNumber:        "",
			CreateBy:        "",
		}).Error; err != nil {
			fmt.Println("提交失败,回滚", err.Error())
			return err
		}
		return nil
	})
	// Error 1062 (23000): Duplicate entry '3bb95b4f-be05-43f4-8a6d-6d288a574dc3' for key 'uni_user_user_id'
	// 这里 UserID 设置了唯一,所以运行的时候会失败,然后整个 Transaction 里面执行的SQL都会回滚
	if err != nil {
		fmt.Println("自动化事务失败", err.Error())
		return
	}

	// 手动化事务
	tx := db.Begin()
	getUUid := utils.RandUuid()
	rowsAffected := tx.Table("user").Create(&models.User{
		UserID:          getUUid,
		TaiUserName:     utils.GetRandChineseName(),
		UserName:        utils.GetRandName(10, false),
		UserChineseName: utils.GetRandChineseName(),
		NeedCard:        0,
		AuthStartDate:   "",
		AuthEndDate:     "",
		Status:          0,
		OrgType:         0,
		UpdateTime:      time.Now(),
		Phone:           "",
		ConcatPeople:    "",
		IDNumber:        "",
		CreateBy:        "",
	}).RowsAffected

	if rowsAffected == 0 {
		tx.Rollback()
		fmt.Println("--1--有效行数为0,回滚")
		return
	}

	rowsAffected2 := tx.Table("user").Create(&models.User{
		UserID:          getUUid,
		TaiUserName:     utils.GetRandChineseName(),
		UserName:        utils.GetRandName(10, false),
		UserChineseName: utils.GetRandChineseName(),
		NeedCard:        0,
		AuthStartDate:   "",
		AuthEndDate:     "",
		Status:          0,
		OrgType:         0,
		UpdateTime:      time.Now(),
		Phone:           "",
		ConcatPeople:    "",
		IDNumber:        "",
		CreateBy:        "",
	}).RowsAffected
	if rowsAffected2 == 0 {
		tx.Rollback()
		fmt.Println("--2--有效行数为0,回滚")
		return
	}
	// Error 1062 (23000): Duplicate entry '3fe813e9-b3c1-48fd-9c51-12a860c5caa2' for key 'uni_user_user_id'
	// 这里第二次失败回滚也会导致整个事务里面的执行SQL回滚
	defer tx.Commit()
}

// GetUserListFromMongo 获取用户列表（带Redis缓存）
func GetUserListFromMongo(c *gin.Context) {
	// --- 新增：Redis 缓存逻辑 ---
	const redisKey = "user_list_key"

	// 1. 尝试从 Redis 获取数据
	// Redis 中存储的是 JSON 字符串，所以这里用 GetString
	redisData, err := utils.RedisDB.Get(context.Background(), redisKey).Result()

	if err == nil {
		// 2. 缓存命中 (err == nil 表示成功获取到值)
		log.Println("缓存命中，直接从Redis返回用户列表")

		// 定义一个切片用于存放从 Redis 解析出的数据
		var userList []models.User
		// 将 JSON 字符串解析到 userList 结构体中
		if err := json.Unmarshal([]byte(redisData), &userList); err != nil {
			log.Printf("从Redis获取的数据JSON解析失败: %v", err)
			// 如果解析失败，我们不能返回错误数据，应该继续执行，去数据库查询
		} else {
			// 解析成功，直接返回数据给客户端
			CommonCJsonReply(c, config.SUCCESS, userList)
			return // 必须 return，终止函数执行
		}
	} else if !errors.Is(err, redis.Nil) {
		// 3. Redis 操作出错 (例如连接失败)
		// 这种情况不是“key不存在”，而是发生了其他错误
		log.Printf("Redis查询失败: %v", err)
		// 我们不应该因为缓存出错而中断主业务，所以这里只记录日志，继续去数据库查询
	}
	// 如果代码执行到这里，说明缓存未命中 (err == redis.Nil) 或缓存解析失败

	// --- 原有：MongoDB 查询逻辑 ---
	log.Println("缓存未命中，从MongoDB查询用户列表")

	var userList []models.User
	collection := utils.MyDataBase.Collection("user")

	cursor, err := collection.Find(context.Background(), bson.D{})
	if err != nil {
		log.Printf("查询MongoDB失败: %v", err)
		CommonCJsonReply(c, config.ERROR, "查询用户列表失败")
		return
	}
	defer cursor.Close(context.Background())

	if err = cursor.All(context.Background(), &userList); err != nil {
		log.Printf("解码MongoDB结果失败: %v", err)
		CommonCJsonReply(c, config.ERROR, "处理用户列表数据失败")
		return
	}

	// 4. 成功从数据库获取数据，返回给客户端
	CommonCJsonReply(c, config.SUCCESS, userList)

	// --- 新增：异步写入 Redis 缓存 ---
	// 使用 goroutine 异步执行，防止阻塞当前请求，影响响应速度
	// 注意：这里需要捕获外部变量 userList
	go func(data []models.User) {
		// 将用户列表结构体序列化为 JSON 字符串
		jsonData, err := json.Marshal(data)
		if err != nil {
			log.Printf("用户列表数据JSON序列化失败: %v", err)
			return
		}

		// 设置 Redis 键值，并可以设置过期时间（例如 10 分钟）
		// 过期时间可以根据业务需求调整，防止缓存数据长期不更新
		err = utils.RedisDB.Set(context.Background(), redisKey, jsonData, 10*time.Minute).Err()
		if err != nil {
			log.Printf("将用户列表写入Redis失败: %v", err)
		} else {
			log.Println("用户列表已成功写入Redis缓存")
		}
	}(userList)
}

func CreateUserMongo(c *gin.Context) {
	// 1. 创建一个用于接收请求数据的变量
	var req dto.CreateUserRequest

	// 2. 使用 ShouldBindJSON 将请求体中的JSON解析到 req 变量中
	// ShouldBindJSON 会自动进行类型转换和基于 "binding" 标签的校验
	if err := c.ShouldBindJSON(&req); err != nil {
		// 如果解析或校验失败，返回错误信息
		fmt.Println("参数解析失败:", err)
		CommonCJsonReply(c, config.ERROR, "无效的请求参数: "+err.Error())
		return // 必须 return，终止函数执行
	}

	// 3. 将解析后的请求数据填充到 models.User 结构体中
	userData := models.User{
		UserID:          req.UserID,
		TaiUserName:     req.TaiUserName,
		UserName:        req.UserName,
		UserChineseName: req.UserChineseName,
		NeedCard:        int8(req.NeedCard),
		AuthStartDate:   req.AuthStartDate,
		AuthEndDate:     req.AuthEndDate,
		Status:          int8(req.Status),
		OrgType:         int8(req.OrgType),
		UpdateTime:      time.Now(), // UpdateTime 由服务器生成
		Phone:           req.Phone,
		ConcatPeople:    req.ConcatPeople,
		IDNumber:        req.IDNumber,
		CreateBy:        req.CreateBy,
	}

	// 4. 选择 collection
	getDatabase := utils.MyDataBase.Collection("user")

	// 5. 插入数据到 MongoDB
	_, err := getDatabase.InsertOne(context.Background(), userData)
	if err != nil {
		fmt.Println("MongoDB 插入失败:", err)
		CommonCJsonReply(c, config.ERROR, "创建用户失败: "+err.Error())
		return
	}

	// 6. 返回成功响应
	CommonCJsonReply(c, config.SUCCESS, "用户创建成功")
}

// RandUser 随机添加用户信息
func RandUser(c *gin.Context) {
	num, _ := strconv.Atoi(c.Query("num"))
	if num <= 0 {
		num = 10
	}
	code := repo.RandUserModel(num)
	c.JSON(
		http.StatusOK, gin.H{
			"status":  code,
			"data":    "随机增加" + strconv.Itoa(num) + "条数据",
			"message": "ok",
		},
	)
}
